class Curve{
	constructor(y=0){
		this.data = [{
			type: "point",
			to: new Vector2(0, y)
		}];
	}
	
	
	
	lineTo(y, delta){
		const last = this.data[this.data.length-1];
		const x0 = last.to.x,
			x1 = x0 + delta,
			y0 = last.to.y;
		
		this.data.push({
			type: "line",
			from: last.to,
			to: new Vector2(x1, y),
			params: [
				(y - y0) / delta,
				(x1 * y0 - x0 * y) / delta
			]
		});
		
		return this;
	}
	
	
	expTo(y, delta, p){
		const last = this.data[this.data.length-1];
		const x0 = last.to.x,
			x1 = x0 + delta,
			y0 = last.to.y;
		
		this.data.push({
			type: "exp",
			from: last.to,
			to: new Vector2(x1, y),
			params: [
				p / delta,
				-p * x0 / delta,
				(y - y0) / (Math.exp(p) - 1),
				y0 - (y - y0) / (Math.exp(p) - 1)
			]
		});
		
		return this;
	}
	
	
	logTo(y, delta, p){
		const last = this.data[this.data.length-1];
		const x0 = last.to.x,
			x1 = x0 + delta,
			y0 = last.to.y;
		
		this.data.push({
			type: "log",
			from: last.to,
			to: new Vector2(x1, y),
			params: [
				(p - 1) / delta,
				1 - (p - 1) * x0 / delta,
				(y - y0) / Math.log(p),
				y0
			]
		});
		
		return this;
	}
	
	
	smoothTo(y, delta){
		const last = this.data[this.data.length-1];
		const x0 = last.to.x,
			x1 = x0 + delta,
			y0 = last.to.y;
		
		this.data.push({
			type: "smooth",
			from: last.to,
			to: new Vector2(x1, y),
			params: [
				1 / delta,
				-x0 / delta,
				y - y0,
				y0
			]
		});
		
		return this;
	}
	
	
	
	//转为js函数
	toFunction(){
		return (x => {
			let find = false;
			for (let i=1; i<this.data.length; ++i){
				const data = this.data[i];
				if (data.from.x > x || x > data.to.x) continue;
				find = true;
				
				switch (data.type){
					case "line":
						return data.params[0] * x + data.params[1];
						break;
					case "exp":
						return data.params[2] * Math.exp(data.params[0] * x + data.params[1]) + data.params[3];
						break;
					case "log":
						return data.params[2] * Math.log(data.params[0] * x + data.params[1]) + data.params[3];
						break;
					case "smooth":
						const u = data.params[0] * x + data.params[1];
						const value = u * u * (3 - 2 * u);
						return value * data.params[2] + data.params[3];
						break;
				}
			}
			if (!find)
				return console.error("[Curve.toFunction] Range Overflow:" + x);
		});
	}
	
	//转为新canvas
	toCanvas(x1, y1, x2, y2, step=1){
		const canvas = document.createElement("canvas");
		canvas.width = x2 - x1;
		canvas.height = y2 - y1;
		
		const ctx = canvas.getContext("2d");
		ctx.strokeStyle = "red";
		this.toCtxOperation(ctx, x1, y1, x2, y2, step=1);
		return canvas;
	}
	
	//转为ctx操作
	toCtxOperation(ctx, x1, y1, x2, y2, step=1){
		const f = this.toFunction();
		ctx.beginPath();
		ctx.moveTo(x1, f(x1));
		for (let x=x1+step; x<=x2; x+=step)
			ctx.lineTo(x, f(x));
		ctx.stroke();
	}
	
	//转为glsl表达式
	toGLSL(varName){
		const toFloat = v =>
			v + (v%1==0? ".0": ""); //转换为浮点格式字符串
		let code = ""; //代码
		
		for (let i=1; i<this.data.length; ++i){
			const data = this.data[i];
			
			code += `${varName} <= ${toFloat(data.to.x)}? `;
			switch (data.type){
				case "line":
					code += `${toFloat(data.params[0])} * ${varName} + ${toFloat(data.params[1])}`;
					break;
				case "exp":
					code += `${toFloat(data.params[2])} * exp(${toFloat(data.params[0])} * ${varName} + ${toFloat(data.params[1])}) + ${toFloat(data.params[3])}`;
					break;
				case "log":
					code += `${toFloat(data.params[2])} * log(${toFloat(data.params[0])} * ${varName} + ${toFloat(data.params[1])}) + ${toFloat(data.params[3])}`;
					break;
				case "smooth":
					code += `lerp(${toFloat(data.from.y)}, ${toFloat(data.to.y)}, smooth(${toFloat(data.from.x)}, ${toFloat(data.to.x)}, ${varName}))`;
			}
			code += ": ";
		}
		code += "0.0";
		return code.trim().split("\n").map(line => line.trim()).join();
	}
	
}